{
const appURLFacts = getAppURLFactsFromRequestURL(req.originalUrl);
const { basePath, baseDomain } = appURLFacts;
const baseURL = basePath.replace(/\/$/, '');
const baseHref = baseDomain + baseURL;
const loadingPromise = getWebpackCompiledRootComponentForSSR();
const hasNotAcknowledgedPoliciesPromise = hasAnyNotAcknowledgedPolicies(
viewer.id,
baseLegalPolicies,
);
let initialNavInfo;
try {
initialNavInfo = navInfoFromURL(req.url, {
now: currentDateInTimeZone(viewer.timeZone),
});
} catch (e) {
throw new ServerError(e.message);
}
const calendarQuery = {
startDate: initialNavInfo.startDate,
endDate: initialNavInfo.endDate,
filters: defaultCalendarFilters,
};
const messageSelectionCriteria = { joinedThreads: true };
const initialTime = Date.now();
const assetInfoPromise = getAssetInfo();
const threadInfoPromise = fetchThreadInfos(viewer);
const messageInfoPromise = fetchMessageInfos(
viewer,
messageSelectionCriteria,
defaultNumberPerThread,
);
const entryInfoPromise = fetchEntryInfos(viewer, [calendarQuery]);
const currentUserInfoPromise = fetchCurrentUserInfo(viewer);
const userInfoPromise = fetchKnownUserInfos(viewer);
const sessionIDPromise = (async () => {
if (viewer.loggedIn) {
await setNewSession(viewer, calendarQuery, initialTime);
}
return viewer.sessionID;
})();
const threadStorePromise = (async () => {
const [{ threadInfos }, hasNotAcknowledgedPolicies] = await Promise.all([
threadInfoPromise,
hasNotAcknowledgedPoliciesPromise,
]);
return { threadInfos: hasNotAcknowledgedPolicies ? {} : threadInfos };
})();
const messageStorePromise = (async () => {
const [
{ threadInfos },
{ rawMessageInfos, truncationStatuses },
hasNotAcknowledgedPolicies,
] = await Promise.all([
threadInfoPromise,
messageInfoPromise,
hasNotAcknowledgedPoliciesPromise,
]);
if (hasNotAcknowledgedPolicies) {
return {
messages: {},
threads: {},
local: {},
currentAsOf: 0,
};
}
const { messageStore: freshStore } = freshMessageStore(
rawMessageInfos,
truncationStatuses,
mostRecentMessageTimestamp(rawMessageInfos, initialTime),
threadInfos,
);
return freshStore;
})();
const entryStorePromise = (async () => {
const [{ rawEntryInfos }, hasNotAcknowledgedPolicies] = await Promise.all([
entryInfoPromise,
hasNotAcknowledgedPoliciesPromise,
]);
if (hasNotAcknowledgedPolicies) {
return {
entryInfos: {},
daysToEntries: {},
lastUserInteractionCalendar: 0,
};
}
return {
entryInfos: _keyBy('id')(rawEntryInfos),
daysToEntries: daysToEntriesFromEntryInfos(rawEntryInfos),
lastUserInteractionCalendar: initialTime,
};
})();
const userStorePromise = (async () => {
const [userInfos, hasNotAcknowledgedPolicies] = await Promise.all([
userInfoPromise,
hasNotAcknowledgedPoliciesPromise,
]);
return {
userInfos: hasNotAcknowledgedPolicies ? {} : userInfos,
inconsistencyReports: [],
};
})();
const navInfoPromise = (async () => {
const [{ threadInfos }, messageStore, currentUserInfo, userStore] =
await Promise.all([
threadInfoPromise,
messageStorePromise,
currentUserInfoPromise,
userStorePromise,
]);
const finalNavInfo = initialNavInfo;
const requestedActiveChatThreadID = finalNavInfo.activeChatThreadID;
if (
requestedActiveChatThreadID &&
!threadIsPending(requestedActiveChatThreadID) &&
!threadHasPermission(
threadInfos[requestedActiveChatThreadID],
threadPermissions.VISIBLE,
)
) {
finalNavInfo.activeChatThreadID = null;
}
if (!finalNavInfo.activeChatThreadID) {
const mostRecentThread = mostRecentlyReadThread(
messageStore,
threadInfos,
);
if (mostRecentThread) {
finalNavInfo.activeChatThreadID = mostRecentThread;
}
}
if (
finalNavInfo.activeChatThreadID &&
threadIsPending(finalNavInfo.activeChatThreadID) &&
finalNavInfo.pendingThread?.id !== finalNavInfo.activeChatThreadID
) {
const pendingThreadData = parsePendingThreadID(
finalNavInfo.activeChatThreadID,
);
if (
pendingThreadData &&
pendingThreadData.threadType !== threadTypes.SIDEBAR &&
currentUserInfo.id
) {
const { userInfos } = userStore;
const members = [...pendingThreadData.memberIDs, currentUserInfo.id]
.map(id => {
const userInfo = userInfos[id];
if (!userInfo || !userInfo.username) {
return undefined;
}
const { username } = userInfo;
return { id, username };
})
.filter(Boolean);
const newPendingThread = createPendingThread({
viewerID: currentUserInfo.id,
threadType: pendingThreadData.threadType,
members,
});
finalNavInfo.activeChatThreadID = newPendingThread.id;
finalNavInfo.pendingThread = newPendingThread;
}
}
return finalNavInfo;
})();
const currentAsOfPromise = (async () => {
const hasNotAcknowledgedPolicies = await hasNotAcknowledgedPoliciesPromise;
return hasNotAcknowledgedPolicies ? 0 : initialTime;
})();
const pushApiPublicKeyPromise = (async () => {
const pushConfig = await getWebPushConfig();
if (!pushConfig) {
if (process.env.NODE_ENV !== 'development') {
console.warn('keyserver/secrets/web_push_config.json should exist');
}
return null;
}
return pushConfig.publicKey;
})();
- const { jsURL, fontsURL, cssInclude, olmFilename } = await assetInfoPromise;
+ const { jsURL, fontsURL, cssInclude, olmFilename, sqljsFilename } =
+ await assetInfoPromise;
// prettier-ignore
res.write(html`
${getTitle(0)}
${cssInclude}
`);
const Loading = await loadingPromise;
const reactStream = renderToNodeStream();
reactStream.pipe(res, { end: false });
await waitForStream(reactStream);
res.write(html`
`);
}
export { websiteResponder };
diff --git a/web/webpack.config.cjs b/web/webpack.config.cjs
index ba21dd1b8..b9f7294f7 100644
--- a/web/webpack.config.cjs
+++ b/web/webpack.config.cjs
@@ -1,139 +1,164 @@
const CopyPlugin = require('copy-webpack-plugin');
const path = require('path');
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
const {
createProdBrowserConfig,
createDevBrowserConfig,
createNodeServerRenderingConfig,
createWebWorkersConfig,
} = require('lib/webpack/shared.cjs');
const babelConfig = require('./babel.config.cjs');
const baseBrowserConfig = {
entry: {
browser: ['./script.js'],
},
output: {
filename: 'prod.[contenthash:12].build.js',
path: path.join(__dirname, 'dist'),
},
resolve: {
alias: {
'../images': path.resolve('../keyserver/images'),
},
fallback: {
crypto: false,
fs: false,
path: false,
},
},
};
const baseDevBrowserConfig = {
...baseBrowserConfig,
output: {
...baseBrowserConfig.output,
filename: 'dev.build.js',
pathinfo: true,
publicPath: 'http://localhost:8080/',
},
devServer: {
port: 8080,
headers: { 'Access-Control-Allow-Origin': '*' },
allowedHosts: ['all'],
host: '0.0.0.0',
static: {
directory: path.join(__dirname, 'dist'),
},
},
plugins: [
new CopyPlugin({
patterns: [
{
from: 'node_modules/@matrix-org/olm/olm.wasm',
to: path.join(__dirname, 'dist'),
},
],
}),
],
};
const baseProdBrowserConfig = {
...baseBrowserConfig,
plugins: [
new CopyPlugin({
patterns: [
{
from: 'node_modules/@matrix-org/olm/olm.wasm',
to: path.join(__dirname, 'dist', 'olm.[contenthash:12].wasm'),
},
],
}),
new WebpackManifestPlugin({
publicPath: '',
}),
],
};
const baseNodeServerRenderingConfig = {
externals: ['react', 'react-dom', 'react-redux'],
entry: {
keyserver: ['./loading.react.js'],
},
output: {
filename: 'app.build.cjs',
library: 'app',
libraryTarget: 'commonjs2',
path: path.join(__dirname, 'dist'),
},
};
const baseWebWorkersConfig = {
- plugins: [
- new CopyPlugin({
- patterns: [
- {
- from: 'node_modules/sql.js/dist/sql-wasm.wasm',
- to: path.join(__dirname, 'dist'),
- },
- ],
- }),
- ],
entry: {
pushNotif: './push-notif/service-worker.js',
database: './database/worker/db-worker.js',
},
output: {
filename: '[name].build.js',
path: path.join(__dirname, 'dist', 'webworkers'),
},
resolve: {
fallback: {
crypto: false,
fs: false,
path: false,
},
},
};
+const devWebWorkersPlugins = [
+ new CopyPlugin({
+ patterns: [
+ {
+ from: 'node_modules/sql.js/dist/sql-wasm.wasm',
+ to: path.join(__dirname, 'dist', 'webworkers'),
+ },
+ ],
+ }),
+];
+
+const prodWebWorkersPlugins = [
+ new CopyPlugin({
+ patterns: [
+ {
+ from: 'node_modules/sql.js/dist/sql-wasm.wasm',
+ to: path.join(
+ __dirname,
+ 'dist',
+ 'webworkers',
+ 'sql-wasm.[contenthash:12].wasm',
+ ),
+ },
+ ],
+ }),
+ new WebpackManifestPlugin({
+ publicPath: '',
+ }),
+];
+
module.exports = function (env) {
const browserConfig = env.prod
? createProdBrowserConfig(baseProdBrowserConfig, babelConfig)
: createDevBrowserConfig(baseDevBrowserConfig, babelConfig);
const nodeConfig = createNodeServerRenderingConfig(
baseNodeServerRenderingConfig,
babelConfig,
);
const nodeServerRenderingConfig = {
...nodeConfig,
mode: env.prod ? 'production' : 'development',
};
+
+ const workersConfig = {
+ ...baseWebWorkersConfig,
+ plugins: env.prod ? prodWebWorkersPlugins : devWebWorkersPlugins,
+ };
const webWorkersConfig = createWebWorkersConfig(
env,
- baseWebWorkersConfig,
+ workersConfig,
babelConfig,
);
return [browserConfig, nodeServerRenderingConfig, webWorkersConfig];
};